<?php

if (!defined('BASEPATH'))
  exit('No direct script access allowed');
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		CodeIgniter
 * @author		EllisLab Dev Team
 * @copyright	Copyright (c) 2006 - 2012, EllisLab, Inc.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://codeigniter.com
 * @since		Version 1.0
 * @filesource
 */
// ------------------------------------------------------------------------

/**
 * CodeIgniter Driver Library Class
 *
 * This class enables you to create "Driver" libraries that add runtime ability
 * to extend the capabilities of a class via additional driver objects
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author		EllisLab Dev Team
 * @link
 */
class CI_Driver_Library {

  protected $valid_drivers = array();
  protected $lib_name;

  // The first time a child is used it won't exist, so we instantiate it
  // subsequents calls will go straight to the proper child.
  function __get($child) {
    if (!isset($this->lib_name)) {
      $this->lib_name = get_class($this);
    }

    // The class will be prefixed with the parent lib
    $child_class = $this->lib_name . '_' . $child;

    // Remove the CI_ prefix and lowercase
    $lib_name = ucfirst(strtolower(str_replace('CI_', '', $this->lib_name)));
    $driver_name = strtolower(str_replace('CI_', '', $child_class));

    if (in_array($driver_name, array_map('strtolower', $this->valid_drivers))) {
      // check and see if the driver is in a separate file
      if (!class_exists($child_class)) {
        // check application path first
        foreach (get_instance()->load->get_package_paths(TRUE) as $path) {
          // loves me some nesting!
          foreach (array(ucfirst($driver_name), $driver_name) as $class) {
            $filepath = $path . 'libraries/' . $lib_name . '/drivers/' . $class . '.php';

            if (file_exists($filepath)) {
              include_once $filepath;
              break;
            }
          }
        }

        // it's a valid driver, but the file simply can't be found
        if (!class_exists($child_class)) {
          log_message('error', "Unable to load the requested driver: " . $child_class);
          show_error("Unable to load the requested driver: " . $child_class);
        }
      }

      $obj = new $child_class;
      $obj->decorate($this);
      $this->$child = $obj;
      return $this->$child;
    }

    // The requested driver isn't valid!
    log_message('error', "Invalid driver requested: " . $child_class);
    show_error("Invalid driver requested: " . $child_class);
  }

  // --------------------------------------------------------------------
}

// END CI_Driver_Library CLASS

/**
 * CodeIgniter Driver Class
 *
 * This class enables you to create drivers for a Library based on the Driver Library.
 * It handles the drivers' access to the parent library
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author		EllisLab Dev Team
 * @link
 */
class CI_Driver {

  protected $parent;
  private $methods = array();
  private $properties = array();
  private static $reflections = array();

  /**
   * Decorate
   *
   * Decorates the child with the parent driver lib's methods and properties
   *
   * @param	object
   * @return	void
   */
  public function decorate($parent) {
    $this->parent = $parent;

    // Lock down attributes to what is defined in the class
    // and speed up references in magic methods

    $class_name = get_class($parent);

    if (!isset(self::$reflections[$class_name])) {
      $r = new ReflectionObject($parent);

      foreach ($r->getMethods() as $method) {
        if ($method->isPublic()) {
          $this->methods[] = $method->getName();
        }
      }

      foreach ($r->getProperties() as $prop) {
        if ($prop->isPublic()) {
          $this->properties[] = $prop->getName();
        }
      }

      self::$reflections[$class_name] = array($this->methods, $this->properties);
    } else {
      list($this->methods, $this->properties) = self::$reflections[$class_name];
    }
  }

  // --------------------------------------------------------------------

  /**
   * __call magic method
   *
   * Handles access to the parent driver library's methods
   *
   * @access	public
   * @param	string
   * @param	array
   * @return	mixed
   */
  public function __call($method, $args = array()) {
    if (in_array($method, $this->methods)) {
      return call_user_func_array(array($this->parent, $method), $args);
    }

    $trace = debug_backtrace();
    _exception_handler(E_ERROR, "No such method '{$method}'", $trace[1]['file'], $trace[1]['line']);
    exit;
  }

  // --------------------------------------------------------------------

  /**
   * __get magic method
   *
   * Handles reading of the parent driver library's properties
   *
   * @param	string
   * @return	mixed
   */
  public function __get($var) {
    if (in_array($var, $this->properties)) {
      return $this->parent->$var;
    }
  }

  // --------------------------------------------------------------------

  /**
   * __set magic method
   *
   * Handles writing to the parent driver library's properties
   *
   * @param	string
   * @param	array
   * @return	mixed
   */
  public function __set($var, $val) {
    if (in_array($var, $this->properties)) {
      $this->parent->$var = $val;
    }
  }

  // --------------------------------------------------------------------
}

// END CI_Driver CLASS

/* End of file Driver.php */
/* Location: ./system/libraries/Driver.php */